package wecom

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"io"
	"log"
	"net/url"
	"strings"
	"time"

	"v2/config"
	"v2/model"

	"github.com/gin-gonic/gin"
)

// HandleWeComAppCallback 处理企业微信应用回调事件
func HandleWeComAppCallback(c *gin.Context) {
	log.Println("[WeComApp] 收到回调请求")

	// 打印完整的请求信息用于调试
	log.Printf("[WeComApp] 完整请求URL: %s", c.Request.URL.String())
	log.Printf("[WeComApp] 请求方法: %s", c.Request.Method)
	log.Printf("[WeComApp] 请求头: %v", c.Request.Header)

	// 打印查询参数
	log.Printf("[WeComApp] 查询参数: %v", c.Request.URL.Query())

	// 初始化变量
	var userID, action, alertToken string

	// 读取请求体
	body, err := io.ReadAll(c.Request.Body)
	if err != nil {
		log.Printf("[WeComApp] 读取请求体失败: %v", err)
		c.JSON(400, gin.H{"error": "读取请求体失败"})
		return
	}

	log.Printf("[WeComApp] 请求体长度: %d 字节", len(body))
	log.Printf("[WeComApp] 请求体内容: %s", string(body))

	// 重新设置请求体，以便后续处理
	c.Request.Body = io.NopCloser(bytes.NewBuffer(body))

	// 检查是否是XML格式
	if len(body) > 0 && (bytes.Contains(body, []byte("<xml>")) || bytes.Contains(body, []byte("<?xml"))) {
		log.Printf("[WeComApp] 检测到XML格式的数据，尝试解析")

		// 解析XML数据
		xmlUserID, xmlAction, xmlToken := parseWeComXMLCallback(body)
		if xmlUserID != "" {
			userID = xmlUserID
			log.Printf("[WeComApp] 从XML中提取到用户ID: %s", userID)
		}
		if xmlAction != "" {
			action = xmlAction
			log.Printf("[WeComApp] 从XML中提取到操作类型: %s", action)
		}
		if xmlToken != "" {
			alertToken = xmlToken
			log.Printf("[WeComApp] 从XML中提取到令牌: %s", alertToken)
		}
	} else {
		log.Printf("[WeComApp] 请求体不是XML格式，尝试从URL参数获取")
		// 如果不是XML格式，尝试从URL参数获取
		userID = c.Query("user_id")
		action = c.Query("action")
		alertToken = c.Query("token")
	}

	// 如果还是没有获取到必要参数，尝试从表单数据中获取
	if userID == "" {
		userID = c.PostForm("user_id")
		if userID == "" {
			userID = c.PostForm("userid")
		}
	}

	if action == "" {
		action = c.PostForm("action")
	}

	if alertToken == "" {
		alertToken = c.PostForm("token")
	}

	// 如果还是没有获取到用户ID，检查是否是企业微信的特殊参数
	if userID == "" {
		// 企业微信在点击按钮时会通过FromUserName字段传递用户ID
		// 但在GET请求中我们无法获取到，所以需要通过其他方式获取
		// 注意：这可能不是最佳实践，但在某些情况下可能是必要的
		if fromUser := c.GetHeader("FromUserName"); fromUser != "" {
			userID = fromUser
			log.Printf("[WeComApp] 从Header中提取到用户ID: %s", userID)
		}
	}

	// 如果还是没有获取到用户ID，使用默认值但记录警告
	if userID == "" {
		userID = "unknown_user"
		log.Printf("[WeComApp] 警告: 未获取到用户ID，使用默认值: %s", userID)
	}

	// 创建企业微信通知器实例用于获取访问令牌和用户信息
	// 修复BaseURL生成逻辑，避免重复端口号
	var baseURL string
	host := c.Request.Host
	if host != "" {
		// 检查host是否已经包含端口号
		if strings.Contains(host, ":") {
			baseURL = fmt.Sprintf("http://%s", host)
		} else {
			baseURL = fmt.Sprintf("http://%s:%d", host, config.Global.Server.Port)
		}
	} else {
		baseURL = fmt.Sprintf("http://localhost:%d", config.Global.Server.Port)
	}

	wecomApp := NewWeComAppNotifier(
		config.Global.Notifier.WeComApp.CorpID,
		config.Global.Notifier.WeComApp.Secret,
		int64(config.Global.Notifier.WeComApp.AgentID), // 修复：确保AgentID为int64类型
		baseURL,
	)

	// 如果获取到了用户ID，尝试获取用户名
	username := userID // 默认使用用户ID作为用户名
	if userID != "unknown_user" {
		// 获取访问令牌
		accessToken, err := wecomApp.GetAccessToken()
		if err != nil {
			log.Printf("[WeComApp] 获取访问令牌失败: %v", err)
		} else {
			// 通过用户ID获取用户名（带缓存）
			name, err := wecomApp.GetUserNameByUIDWithCache(accessToken, userID)
			if err != nil {
				log.Printf("[WeComApp] 通过用户ID获取用户名失败: %v", err)
				// 如果无法获取用户名，继续使用用户ID
			} else {
				username = name
				log.Printf("[WeComApp] 成功获取用户名: %s -> %s", userID, username)
			}
		}
	}

	if action == "" {
		log.Printf("[WeComApp] 缺少必要参数: action")
		c.JSON(400, gin.H{"error": "缺少必要参数"})
		return
	}

	log.Printf("[WeComApp] 处理操作: %s, token: %s, 用户ID: %s, 用户名: %s",
		action, alertToken, userID, username)

	// 获取告警信息
	alert, err := wecomApp.GetAlertInfo(alertToken)
	if err != nil {
		log.Printf("[WeComApp] 获取告警信息失败: %v", err)
		c.JSON(400, gin.H{"error": "告警信息不存在或已过期"})
		return
	}

	// 显式引用model包以满足编译器要求
	_ = (*model.AlertInfo)(nil)

	// 在执行操作前先记录操作尝试
	currentTime := time.Now().Format("2006-01-02 15:04:05")
	var operationNotes string
	switch action {
	case "claim":
		operationNotes = fmt.Sprintf("用户%s(%s) 尝试认领告警 [%s]", username, userID, currentTime)
	case "mute2":
		operationNotes = fmt.Sprintf("用户%s(%s) 尝试屏蔽2小时告警 [%s]", username, userID, currentTime)
	case "mute24":
		operationNotes = fmt.Sprintf("用户%s(%s) 尝试屏蔽24小时告警 [%s]", username, userID, currentTime)
	case "complete":
		operationNotes = fmt.Sprintf("用户%s(%s) 尝试完成告警 [%s]", username, userID, currentTime)
	default:
		operationNotes = fmt.Sprintf("用户%s(%s) 尝试执行操作: %s [%s]", username, userID, action, currentTime)
	}

	// 追加操作记录到Redis
	if err := wecomApp.AppendOperationRecord(alertToken, operationNotes); err != nil {
		log.Printf("[WeComApp] 追加操作记录失败: %v", err)
		// 不中断主流程
	}

	// 创建夜莺客户端
	nightingaleClient := NewNightingaleClient() // 修复：通过wecom包调用NewNightingaleClient

	// 根据操作类型处理不同操作
	var responseMsg string

	switch action {
	case "claim":
		notes := fmt.Sprintf("企业微信用户 %s(%s) 认领告警 [%s]", username, userID, currentTime)
		err = nightingaleClient.ClaimAlert(alert.ID, userID, notes)
		if err != nil {
			// 记录失败的操作
			failNotes := fmt.Sprintf("用户%s(%s) 认领告警失败: %v [%s]", username, userID, err, time.Now().Format("2006-01-02 15:04:05"))
			wecomApp.AppendOperationRecord(alertToken, failNotes)

			log.Printf("[WeComApp] 认领告警失败: %v", err)
			c.JSON(500, gin.H{"error": "认领告警失败", "detail": err.Error()})
			return
		}
		responseMsg = "告警已成功认领"
		// 记录成功的操作
		successNotes := fmt.Sprintf("用户%s(%s) 成功认领告警 [%s]", username, userID, time.Now().Format("2006-01-02 15:04:05"))
		wecomApp.AppendOperationRecord(alertToken, successNotes)

	case "mute2":
		notes := fmt.Sprintf("企业微信用户 %s(%s) 屏蔽告警2小时 [%s]", username, userID, currentTime)
		err = nightingaleClient.MuteAlert(*alert, userID, notes, config.Global.Nightingale.MuteDuration2h)
		if err != nil {
			// 记录失败的操作
			failNotes := fmt.Sprintf("用户%s(%s) 屏蔽2小时告警失败: %v [%s]", username, userID, err, time.Now().Format("2006-01-02 15:04:05"))
			wecomApp.AppendOperationRecord(alertToken, failNotes)

			log.Printf("[WeComApp] 屏蔽告警2小时失败: %v", err)
			c.JSON(500, gin.H{"error": "屏蔽告警失败", "detail": err.Error()})
			return
		}
		responseMsg = "告警已屏蔽2小时"
		// 记录成功的操作
		successNotes := fmt.Sprintf("用户%s(%s) 成功屏蔽2小时告警 [%s]", username, userID, time.Now().Format("2006-01-02 15:04:05"))
		wecomApp.AppendOperationRecord(alertToken, successNotes)

	case "mute24":
		notes := fmt.Sprintf("企业微信用户 %s(%s) 屏蔽告警24小时 [%s]", username, userID, currentTime)
		err = nightingaleClient.MuteAlert(*alert, userID, notes, config.Global.Nightingale.MuteDuration24h)
		if err != nil {
			// 记录失败的操作
			failNotes := fmt.Sprintf("用户%s(%s) 屏蔽24小时告警失败: %v [%s]", username, userID, err, time.Now().Format("2006-01-02 15:04:05"))
			wecomApp.AppendOperationRecord(alertToken, failNotes)

			log.Printf("[WeComApp] 屏蔽告警24小时失败: %v", err)
			c.JSON(500, gin.H{"error": "屏蔽告警失败", "detail": err.Error()})
			return
		}
		responseMsg = "告警已屏蔽24小时"
		// 记录成功的操作
		successNotes := fmt.Sprintf("用户%s(%s) 成功屏蔽24小时告警 [%s]", username, userID, time.Now().Format("2006-01-02 15:04:05"))
		wecomApp.AppendOperationRecord(alertToken, successNotes)

	case "complete":
		notes := fmt.Sprintf("企业微信用户 %s(%s) 完成告警 [%s]", username, userID, currentTime)
		err = nightingaleClient.CompleteAlert(alert.ID, userID, notes)
		if err != nil {
			// 记录失败的操作
			failNotes := fmt.Sprintf("用户%s(%s) 完成告警失败: %v [%s]", username, userID, err, time.Now().Format("2006-01-02 15:04:05"))
			wecomApp.AppendOperationRecord(alertToken, failNotes)

			log.Printf("[WeComApp] 完成告警失败: %v", err)
			c.JSON(500, gin.H{"error": "完成告警失败", "detail": err.Error()})
			return
		}
		responseMsg = "告警已完成"
		// 记录成功的操作
		successNotes := fmt.Sprintf("用户%s(%s) 成功完成告警 [%s]", username, userID, time.Now().Format("2006-01-02 15:04:05"))
		wecomApp.AppendOperationRecord(alertToken, successNotes)

	default:
		log.Printf("[WeComApp] 未知操作类型: %s", action)
		c.JSON(400, gin.H{"error": "未知操作类型"})
		return
	}

	if err != nil {
		log.Printf("[WeComApp] 处理操作失败: %v", err)
		c.JSON(500, gin.H{"error": err.Error()})
		return
	}

	// 更新卡片显示操作记录
	log.Printf("[WeComApp] 开始更新卡片: token=%s, action=%s, userID=%s, username=%s", alertToken, action, userID, username)
	err = wecomApp.UpdateCard(alertToken, action, userID, *alert)
	if err != nil {
		log.Printf("[WeComApp] 更新卡片失败: %v", err)
		// 即使更新卡片失败，也要返回成功，因为核心操作已经完成
		// 但可以在响应中包含卡片更新失败的信息
		log.Printf("[WeComApp] 操作处理成功: %s", responseMsg)
		c.JSON(200, gin.H{
			"message":            responseMsg,
			"success":            true,
			"action":             action,
			"time":               currentTime,
			"card_update_status": "failed",
			"card_update_error":  err.Error(),
		})
		return
	} else {
		log.Printf("[WeComApp] 卡片更新成功")
	}

	log.Printf("[WeComApp] 操作处理成功: %s", responseMsg)
	c.JSON(200, gin.H{
		"message":            responseMsg,
		"success":            true,
		"action":             action,
		"time":               currentTime,
		"card_update_status": "success",
	})
}

// 企业微信XML回调数据解析
func parseWeComXMLCallback(xmlData []byte) (userID, action, token string) {
	// 定义企业微信XML回调数据结构
	type WeComXMLCallback struct {
		ToUserName   string `xml:"ToUserName"`
		FromUserName string `xml:"FromUserName"`
		CreateTime   string `xml:"CreateTime"`
		MsgType      string `xml:"MsgType"`
		Event        string `xml:"Event"`
		EventKey     string `xml:"EventKey"`
		AgentID      string `xml:"AgentID"`
		UserID       string `xml:"UserID"`
		TaskID       string `xml:"TaskId"`
		// 添加其他可能的字段
	}

	var callback WeComXMLCallback
	if err := xml.Unmarshal(xmlData, &callback); err != nil {
		log.Printf("[WeComApp] XML解析失败: %v", err)
		return "", "", ""
	}

	log.Printf("[WeComApp] 解析到的XML数据: %+v", callback)

	// 提取用户ID
	if callback.FromUserName != "" {
		userID = callback.FromUserName
	} else if callback.UserID != "" {
		userID = callback.UserID
	}

	// 从EventKey或其他字段中提取action和token
	// 企业微信的EventKey通常包含回调参数，格式如"action=claim&token=xxx"
	if callback.EventKey != "" {
		// 解析EventKey中的参数
		params, err := url.ParseQuery(callback.EventKey)
		if err == nil {
			if actionParam := params.Get("action"); actionParam != "" {
				action = actionParam
			}
			if tokenParam := params.Get("token"); tokenParam != "" {
				token = tokenParam
			}
		}
	}

	// 如果EventKey中没有找到，尝试从TaskID字段获取token
	// TaskID是我们发送卡片时设置的alertToken
	if token == "" && callback.TaskID != "" {
		token = callback.TaskID
	}

	// 如果EventKey中没有找到action，尝试从Event字段获取action
	if action == "" && callback.Event != "" {
		action = callback.Event
	}

	// 特殊处理：如果Event是template_card_event，说明是模板卡片事件
	// 此时EventKey可能包含按钮的key值
	if callback.Event == "template_card_event" && callback.EventKey != "" {
		// 按钮的key值就是action
		action = callback.EventKey
	}

	return userID, action, token
}
